//存储 组件列表数据
import { createSlice, nanoid, PayloadAction } from "@reduxjs/toolkit";
import { produce } from "immer";
import cloneDeep from "lodash.clonedeep";
import { ComponentPropsType } from "../../components/QuestionComponents";
import {getNextSelectedId, insertNewComponent} from './utils'
import { arrayMove } from "@dnd-kit/sortable";

export type ComponentInfoType = {
  fe_id: string // 前端生成的 id ，服务端 Mongodb 不认这种格式，所以自定义一个 fe_id
  type: string
  title?: string
  isHidden?: boolean //是否隐藏
  isLocked?: boolean //是否锁定
  props: ComponentPropsType
}

export type ComponentsStateType = {
  selectedId: string
  componentList: Array<ComponentInfoType>
  copiedComponent:ComponentInfoType|null;
};
const INIT_STATE: ComponentsStateType = {
  selectedId: "", //选中 的组件的id
  componentList: [],
  copiedComponent:null,
};
export const componentsSlice = createSlice({
  name: "components",
  initialState: INIT_STATE,
  reducers: {
     // 重置所有组件
    resetComponents: (state: ComponentsStateType, action: PayloadAction<ComponentsStateType>) => {
      return action.payload
    },
    // 修改 selectedId
    changeSelectedId: produce((draft: ComponentsStateType, action: PayloadAction<string>) => {
      draft.selectedId = action.payload
    }),
    //添加新组件
    addComponent:produce((draft:ComponentsStateType,action:PayloadAction<ComponentInfoType>)=>{
      const newComponent=action.payload
      insertNewComponent(draft,newComponent)
    }),
    //修改组件属性
    changeComponentProps:produce((draft:ComponentsStateType,action:PayloadAction<{fe_id:string,newProps:ComponentPropsType}>)=>{
      const {fe_id,newProps}=action.payload
      //当前要修改属性的组件
      const curComp=draft.componentList.find(c=>c.fe_id===fe_id)
      if(curComp){
         curComp.props={
          ...curComp.props,
          ...newProps
         }
      }
    }),
    //删除选中的组件
    removeSelectedComponent:produce((draft:ComponentsStateType)=>{
      const {componentList=[],selectedId:removeId}=draft
      //重新计算selectedId
      const newSelectedId=getNextSelectedId(removeId,componentList)
      draft.selectedId=newSelectedId
      const index=componentList.findIndex(c=>c.fe_id===removeId)
      componentList.splice(index,1)
    }),
    //隐藏显示组件
    changeComponentHidden:produce((draft:ComponentsStateType,action:PayloadAction<{fe_id:string,isHidden:boolean}>)=>{
      const {componentList=[]}=draft
      const {fe_id,isHidden}=action.payload
      //隐藏之后重新计算 selectedId
      let newSelectedId=''
      if(isHidden){
        //要隐藏
         newSelectedId=getNextSelectedId(fe_id,componentList)
      }else{
        //要显示
        newSelectedId=fe_id
      }
      draft.selectedId=newSelectedId
      const curComp=componentList.find(c=>c.fe_id===fe_id)
      if(curComp){
        curComp.isHidden=isHidden
      }
    }),
    //锁定
    toggleComponentLock:produce((draft:ComponentsStateType,action:PayloadAction<{fe_id:string}>)=>{
const {componentList=[]}=draft
      const {fe_id}=action.payload
      const curComp=componentList.find(c=>c.fe_id===fe_id)
      if(curComp){
        curComp.isLocked=!curComp.isLocked
      }
    }),
    // 拷贝当前选中的组件
    copySelectedComponent: produce((draft: ComponentsStateType) => {
      const { selectedId, componentList = [] } = draft
      const selectedComponent = componentList.find(c => c.fe_id === selectedId)
      if (selectedComponent == null) return
      draft.copiedComponent = cloneDeep(selectedComponent) // 深拷贝
    }),

    // 粘贴组件
    pasteCopiedComponent: produce((draft: ComponentsStateType) => {
      const { copiedComponent } = draft
      if (copiedComponent == null) return

      // 要把 fe_id 给修改了，重要！！
      copiedComponent.fe_id = nanoid()

      // 插入 copiedComponent
      insertNewComponent(draft, copiedComponent)
    }),
    //选中上一个
    selectedPrevComponent:produce((draft:ComponentsStateType)=>{
      const {selectedId,componentList}=draft
      const selectedIndex=componentList.findIndex(c=>c.fe_id===selectedId)
      if(selectedIndex<0) return //未选中
      if(selectedIndex<=0) return //第一个不能向上
      draft.selectedId=componentList[selectedIndex-1].fe_id
    }),
    //选中下一个
    selectedNextComponent:produce((draft:ComponentsStateType)=>{
      const {selectedId,componentList}=draft
      const selectedIndex=componentList.findIndex(c=>c.fe_id===selectedId)
      const length=componentList.length
      if(selectedIndex<0) return //未选中
      if(selectedIndex+1===length) return //最后一个不能向下
      draft.selectedId=componentList[selectedIndex+1].fe_id
    }),
     // 修改组件标题
    changeComponentTitle: produce(
      (draft: ComponentsStateType, action: PayloadAction<{ fe_id: string; title: string }>) => {
        const { title, fe_id } = action.payload
        const curComp = draft.componentList.find(c => c.fe_id === fe_id)
        if (curComp) curComp.title = title
      }
    ),
    //移动组件位置
    moveComponent:produce((draft:ComponentsStateType,action:PayloadAction<{oldIndex:number,newIndex:number}>)=>{
      const {componentList:curComponentList}=draft
      const {oldIndex,newIndex}=action.payload
      draft.componentList=arrayMove(curComponentList, oldIndex, newIndex)
    })
  },
});
export const { 
  resetComponents,
  changeSelectedId ,
  addComponent,
  changeComponentProps,
  removeSelectedComponent,
  changeComponentHidden,
  toggleComponentLock,
  copySelectedComponent,
  pasteCopiedComponent,
  selectedPrevComponent,
  selectedNextComponent,
  changeComponentTitle,
  moveComponent,
} = componentsSlice.actions;
export default componentsSlice.reducer;
